package hust.hbhmzy.udpchat;

import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.SocketException;
import java.net.UnknownHostException;
import java.util.Arrays;

import android.media.AudioFormat;
import android.media.AudioManager;
import android.media.AudioRecord;
import android.media.AudioTrack;
import android.media.MediaRecorder;
import android.util.Base64;
import android.util.Log;

public class AudioCall {

	private static final String LOG_TAG = "AudioCall";
	private static final int SAMPLE_RATE = 8000; // 采样频率
	private static final int SAMPLE_INTERVAL = 20; // 毫秒
	private static final int SAMPLE_SIZE = 2; // Bytes
	private static final int BUF_SIZE = SAMPLE_INTERVAL * SAMPLE_INTERVAL * SAMPLE_SIZE * 2; //1600 Bytes
	private InetAddress address; // 通话的ip
	private int port = 50000; // 通话端口
	private boolean mic = false; // 是否在录音
	private boolean speakers = false; // 是否在播放
	int speexLen = 1024;//一帧音频编码后的byte长度（20ms）与编码质量有关:Speex.open(int compression);
	int oneFrameSize = 1024;//窄带160,宽带320,超宽带640
	int sendbufSize,recbufSize;
	SpeexUtil speex =SpeexUtil.getInstance();

	public AudioCall(InetAddress address) {

		this.address = address;
	}

	public void startCall() {

		startMic();
		startSpeakers();
	}

	public void endCall() {

		Log.i(LOG_TAG, "Ending call!");
		muteMic();
		muteSpeakers();
	}

	public void muteMic() {

		mic = false;
	}

	public void muteSpeakers() {

		speakers = false;
	}

	//开启麦克风进行录音
	public void startMic() {
		mic = true;
		Thread thread = new Thread(new Runnable() {

			@Override
			public void run() {
				// 创建一个录音线程
				Log.i(LOG_TAG, "Send thread started. Thread id: " + Thread.currentThread().getId());
				// AudioRecord(int audioSource(录音来源), int sampleRateInHz(采样频率), int channelConfig(音频通道),
				//             int audioFormat(指定返回音频数据的格式), int bufferSizeInBytes(录音时音频数据写入的buffer的大小))
				sendbufSize = AudioRecord.getMinBufferSize(SAMPLE_RATE, AudioFormat.CHANNEL_IN_MONO, AudioFormat.ENCODING_PCM_16BIT);
				AudioRecord audioRecorder = new AudioRecord (MediaRecorder.AudioSource.VOICE_COMMUNICATION, SAMPLE_RATE,
						AudioFormat.CHANNEL_IN_MONO, AudioFormat.ENCODING_PCM_16BIT,sendbufSize*10);
				oneFrameSize = speex.getFrameSize();
				Log.e("oneFrameSize", String.valueOf(oneFrameSize));
				int short_read = 0;//存储长度
				short[] buf = new short[oneFrameSize];//存放录制内容
				byte[] speexData = new byte[oneFrameSize];
				try {
					//创建udpsocket包 datagramSocket存放录制的数据，之后进行传输
					Log.i(LOG_TAG, "Packet destination: " + address.toString());
					DatagramSocket socket = new DatagramSocket();
					audioRecorder.startRecording();// 开始录制
					while(mic) {
						// Capture audio from the mic and transmit it
						short_read = audioRecorder.read(buf, 0, oneFrameSize);
						short[] data = new short[short_read];
						System.arraycopy(buf, 0, data, 0, short_read);
						//使用speex把录音的short数组进行编码压缩，返回byte数组
						speexLen = speex.encode(data, 0, speexData, data.length);
						byte[] oneFrameSpeex = new byte[speexLen];
						System.arraycopy(speexData, 0, oneFrameSpeex, 0, speexLen);
//						buf1 = buf;
//						//加密
//						buf1=baceByte(buf);
//						Log. i("SendY", Arrays.toString(buf));
//						Log. e("SendE", Arrays.toString(buf1));

						//将byte数组放入DatagramPacket中，进行传输
						DatagramPacket packet = new DatagramPacket(oneFrameSpeex, speexLen, address, port);
						Log.i(LOG_TAG, "Packet send: " + packet.getLength());
						Log.i(LOG_TAG, "Packet send: " + Arrays.toString(packet.getData()));
						socket.send(packet);
						Thread.sleep(SAMPLE_INTERVAL, 0);
					}
					// 停止接收并释放资源
					audioRecorder.stop();
					audioRecorder.release();
					socket.disconnect();
					socket.close();
					mic = false;
					return;
				}
				catch(InterruptedException e) {

					Log.e(LOG_TAG, "InterruptedException: " + e.toString());
					mic = false;
				}
				catch(SocketException e) {

					Log.e(LOG_TAG, "SocketException: " + e.toString());
					mic = false;
				}
				catch(UnknownHostException e) {

					Log.e(LOG_TAG, "UnknownHostException: " + e.toString());
					mic = false;
				}
				catch(IOException e) {

					Log.e(LOG_TAG, "IOException: " + e.toString());
					mic = false;
				}
			}
		});
		thread.start();
	}

	public void startSpeakers() {
		//开启一个线程接收数据并播放
		if(!speakers) {

			speakers = true;
			Thread receiveThread = new Thread(new Runnable() {

				@Override
				public void run() {
					// 创建一个AudioTrack, 用来播放 传送过来解码后的数据
					Log.i(LOG_TAG, "Receive thread started. Thread id: " + Thread.currentThread().getId());
					recbufSize = AudioTrack.getMinBufferSize(SAMPLE_RATE,AudioFormat.CHANNEL_OUT_MONO,AudioFormat.ENCODING_PCM_16BIT);
					AudioTrack track = new AudioTrack(AudioManager.STREAM_VOICE_CALL, SAMPLE_RATE, AudioFormat.CHANNEL_OUT_MONO,
							AudioFormat.ENCODING_PCM_16BIT,recbufSize , AudioTrack.MODE_STREAM);
					oneFrameSize = speex.getFrameSize();
					track.play();
					try {
						// 定义一个sock来接收数据
						DatagramSocket socket = new DatagramSocket(port);
						byte[] rbuf = new byte[38];
						Log.e(LOG_TAG, "rbuf  length"+String.valueOf(rbuf.length));
						while(speakers) {
							// Play back the audio received from packets
							DatagramPacket packet = new DatagramPacket(rbuf, rbuf.length);
							socket.receive(packet);
							byte[] receviebyte = new byte[speexLen];
							System.arraycopy(packet.getData(), 0, receviebyte, 0, packet.getLength());
							Log.i(LOG_TAG, "Packet received: " + packet.getLength());
							Log.i(LOG_TAG, "Packet received: " + Arrays.toString(receviebyte));
							//解密并播放
//							byte[] buf1 = new byte[packet.getData().length];
//							buf1=dbaceByte(packet.getData());
//							Log. e("ArriveD", Arrays.toString(buf1));

							short[] linn = new short[oneFrameSize];

							speex.decode(receviebyte,linn,rbuf.length);

							track.write(linn, 0, linn.length);

						}
						// 停止播放并释放资源
						socket.disconnect();
						socket.close();
						track.stop();
						track.flush();
						track.release();
						speakers = false;
						return;
					}
					catch(SocketException e) {

						Log.e(LOG_TAG, "SocketException: " + e.toString());
						speakers = false;
					}
					catch(IOException e) {

						Log.e(LOG_TAG, "IOException: " + e.toString());
						speakers = false;
					}
				}
			});
			receiveThread.start();
		}
	}
	//使用java自带的base64加密效果良好。转换方式为每6位字节对应一个字符.
	// 不足位的后面补0.6位字节转换为十进制数值.范围是0-63,对应64个字符.
	// 如果有不足位的,在编码后会补上数量对应的=
	public static byte[] baceByte(byte[] buff) {
		byte[] b;
		b= Base64.encode(buff,Base64.DEFAULT);
		return b;
	}
	public static byte[] dbaceByte(byte[] buff) {
		byte[] b;
		b=Base64.decode(buff,Base64.DEFAULT);
		return b;
	}
	public static short[] toShortArray(byte[] src) {

		int count = src.length >> 1;
		short[] dest = new short[count];
		for (int i = 0; i < count; i++) {//
			dest[i] = (short) (src[i * 2] & 0xff | (src[2 * i + 1] << 8));
		}
		return dest;
	}
	public static byte[] toByteArray(short[] src) {

		int count = src.length;
		byte[] dest = new byte[count << 1];
		for (int i = 0; i < count; i++) {//fffc
			dest[i * 2] = (byte) (src[i] >> 0);
			dest[i * 2 + 1] = (byte) (src[i] >> 8);//fcff
		}

		return dest;
	}
}